package net.tv90.volunteerserveradmin.service;


import cn.dev33.satoken.stp.StpUtil;
import jakarta.annotation.Resource;
import jakarta.persistence.criteria.Predicate;
import lombok.extern.slf4j.Slf4j;
import net.tv90.volunteerserveradmin.dao.StudentRepository;
import net.tv90.volunteerserveradmin.dao.UserRepository;
import net.tv90.volunteerserveradmin.exception.ServiceException;
import net.tv90.volunteerserveradmin.model.domain.Student;
import net.tv90.volunteerserveradmin.model.domain.User;
import net.tv90.volunteerserveradmin.model.dto.StudentDTO;
import net.tv90.volunteerserveradmin.model.dto.StudentQueryDTO;
import net.tv90.volunteerserveradmin.utils.RedisUtils;
import net.tv90.volunteerserveradmin.utils.entity.PageResult;
import net.tv90.volunteerserveradmin.model.vo.StudentVO;
import net.tv90.volunteerserveradmin.utils.entity.Assert;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class StudentService {

    @Resource
    private StudentRepository studentRepository;
    @Resource
    private UserRepository userRepository;
    @Resource
    private RedisUtils redisUtils;

    public StudentVO getStudentById(Long id) {
        Student student = studentRepository.findById(id)
                .orElseThrow(() -> new ServiceException("学生不存在", HttpStatus.OK));
        User user = userRepository.findById(Objects.requireNonNullElse(student.getUserId(), -1L))
                .orElse(User.newUser());
        return new StudentVO(student, user);
    }

    public List<StudentVO> getAllStudents() {
        List<Student> students = studentRepository.findAll();
        return students.stream()
                .map(student -> {
                    User user = userRepository.findById(Objects.requireNonNullElse(student.getUserId(), -1L))
                            .orElse(User.newUser());
                    return new StudentVO(student, user);
                })
                .collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public void addStudent(StudentDTO studentDTO) {
        Assert.assertNotNull("学生信息不能为空", HttpStatus.OK, studentDTO);
        Student student = new Student();
        BeanUtils.copyProperties(studentDTO, student);
        studentRepository.save(student);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateStudent(Long id, StudentDTO studentDTO) {
        Student student = studentRepository.findById(id)
                .orElseThrow(() -> new ServiceException("学生不存在", HttpStatus.OK));
        BeanUtils.copyProperties(studentDTO, student);
        studentRepository.save(student);
        deleteStudentCache(id);
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteStudent(Long id) {
        Student student = studentRepository.findById(id)
                .orElseThrow(() -> new ServiceException("学生不存在", HttpStatus.OK));
        User user = userRepository.findById(Objects.requireNonNullElse(student.getUserId(), -1L)).orElse(null);
        if(user != null) {
            throw new ServiceException("该学生已绑定用户" + user.getUsername() + "，无法删除");
        }
        studentRepository.delete(student);
        deleteStudentCache(id);
    }

    public PageResult<StudentVO> queryStudent(StudentQueryDTO dto) {
        if (dto.getPage() == null || dto.getPage() < 1) {
            dto.setPage(1);
        }
        if (dto.getPageNum() == null || dto.getPageNum() < 10 || dto.getPageNum() > 100) {
            dto.setPageNum(10);
        }
        if (dto.getOrderBy() == null || dto.getOrderBy().isEmpty()) {
            dto.setOrderBy("id");
        }
        if (dto.getDesc() == null) {
            dto.setDesc(0);
        }
        if (dto.getEnrollmentYear() == 0) {
            dto.setEnrollmentYear(null);
        }

        Sort sort = dto.getDesc() == 1 ? Sort.by(dto.getOrderBy()).descending() : Sort.by(dto.getOrderBy()).ascending();
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getPageNum(), sort);

        // 构建 Specification
        Specification<Student> spec = (root, query, criteriaBuilder) -> {
            Predicate predicate = criteriaBuilder.conjunction();

            // 根据学号过滤
            if (dto.getStudentNumber() != null && !dto.getStudentNumber().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("studentNumber"), dto.getStudentNumber()));
            }

            // 根据姓名过滤
            if (dto.getName() != null && !dto.getName().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("name"), "%" + dto.getName() + "%"));
            }

            // 根据性别过滤
            if (dto.getGender() != null && !dto.getGender().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("gender"), dto.getGender()));
            }

            // 根据专业过滤
            if (dto.getMajor() != null && !dto.getMajor().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("major"), "%" + dto.getMajor() + "%"));
            }

            // 根据入学年份过滤
            if (dto.getEnrollmentYear() != null) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("enrollmentYear"), dto.getEnrollmentYear()));
            }

            // 根据地址过滤
            if (dto.getAddress() != null && !dto.getAddress().isEmpty()) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.like(root.get("address"), "%" + dto.getAddress() + "%"));
            }

            return predicate;
        };

        // 查询并返回分页结果
        Page<Student> studentPage = studentRepository.findAll(spec, pageRequest);

        // 将查询结果转换为 StudentVO
        List<StudentVO> list = studentPage.getContent().stream()
                .map(student -> {
                    User user = userRepository.findById(Objects.requireNonNullElse(student.getUserId(), -1L))
                            .orElse(User.newUser());
                    return new StudentVO(student, user);
                })
                .collect(Collectors.toList());
        return new PageResult<>(list, studentPage.getTotalElements());
    }

    @Transactional(rollbackFor = Exception.class)
    public void batchAddStudents(List<StudentDTO> studentDTOList) {
        List<Student> students = studentDTOList.stream().map(dto -> {
            Student student = new Student();
            BeanUtils.copyProperties(dto, student);
            return student;
        }).collect(Collectors.toList());
        studentRepository.saveAll(students);
    }

    public void deleteStudentCache(Long id) {
        String redisUserKey = "student::status::" + id;
        redisUtils.deleteObject(redisUserKey);
    }

    public StudentVO getStudentSelfById(Long studentId) {
        Long userId = StpUtil.getLoginIdAsLong();
        Student student = studentRepository.findById(studentId)
                .orElseThrow(() -> new ServiceException("学生不存在", HttpStatus.OK));
        if(!Objects.equals(userId, student.getUserId())) {
            throw new ServiceException("无法查看他人信息！");
        }
        User user = userRepository.findById(student.getUserId())
                .orElse(User.newUser());
        return new StudentVO(student, user);
    }
}
